/*##############################################
#                                               #
#	  MultiPlayer Notepad 0.02 - Server         #
#    Colpaert Pieter - Vansteenlandt Jan        #
#         GPLv3      - (c) 2009                 #
# Docs used:                                    #
#  http://www.linuxhowtos.org/C_C++/socket.htm  #
#                                               #
 ##############################################*/

#include <iostream>
#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h>
#include <string>
#include <stdlib.h>
 
//our config file
#include "../config.cpp"
//our own class
#include "slots.cpp"

using namespace std;

//exceptionhandling C-style
void error(char *msg)
{
    perror(msg);
    exit(1);
}

void menu(){
	//this proc should show the welcome message.
	cout << "Welcome to Multiplayer notepad! This is the server application, so you probably want to set up a server" << endl;
	cout << "Doing that now ..." <<endl;
}

//
// On first reading, skip this, it's called uppon in the script later on
//

void forkedprocess(int sock, Slots &clients){
	//one process will check on incomming messages
	//another will check on messages to send
	//new int to check how many times we ran through the while
	int time = 0;
	int time2= 0;
    //this number reports the number of char actually have been sent
	int charsent;
    while(true){
    	if(clients.changed() == clients.clientid()){
				//*****  here comes the code to send messages to a client he should receive  *****
				//when connected, we should send a start message with all the information the client should know
				//now we have to create 1 string which contains all information
				//first char: number of cursors to report
				//HIER VERDER DOCUMENTEREN
				//size of the message in integer
				string message = clients.showmessage(); 
 				int sizemessage = message.size();
				//first we send the client how many characters we will send
				char lengthmessage[6];
				//replaces itoa 
				lengthmessage[6]=0;
				int bufff=sizemessage;
				for(int i=0;i<6;i++){
					lengthmessage[5-i]='0' + bufff%10;
					bufff/=10;
				}
				charsent = write(sock, lengthmessage,6);
				if(charsent <= 1) error("error writing to socket: number of characters to send");
				//then we send the message itself
				charsent = write(sock, message.c_str(), sizemessage);
				if(charsent <= 1) error("error writing to socket: message to send");
				//update time, just for fun
				time++;
		}
    		//***** here comes the code to receive and handle messages a client has sent *****
    		//when connected, the server should receive information about the client
	    	int n;
	    	
	    	if(time2 == 0){
  				char buffer3[256]; 
   	  			n = read(sock, buffer3, 255);
   	  			clients.changename(buffer3);
   	  			if (n < 0) error("ERROR reading from socket");
   	  		} 
   	  		else{
   	  			char buffer[256];
   	  			bzero(buffer, 256);
   	  			string dink;
   	  			cin >> dink;
   	  			n = read(sock, buffer, 255);
   	  			
   	  			cout << "LEES DIT: "<< buffer << endl;
   	  			if (n < 0) error("ERROR reading from socket");
   	  			//doorgestuurde informatie via buffer
   	  			//voor de serverlog:
   	  			cout << "Time: " << time <<" Client " << clients.clientid() << " says: " << buffer;
   	  			string buffer2 = buffer;
   	  			string message2;
   	  			if(buffer2.substr(0,5) == "!name"){
   	  				clients.changename(buffer2.substr(6,buffer2.size()-6));
   	  				cout << "Time: " << time << " Client " << clients.clientid() <<  " changed his name into: " << clients.whois() << endl;
   	  			}
   	  			else if(buffer2.substr(0,5) == "!help"){
					//WHEN ASKED FOR HELP
   	  			}
   	  			else{
					//ALS NIETS
   	  			}		
   	 		}
   	 		time2++;
    		time++;
		}	
}


/******************************************************************************************************************************/
/********************                                SERVER APPLICATION MAIN                                 ******************/
/******************************************************************************************************************************/
int main(){
	//first we'll show the menu
	menu();

	//we created a class (C++ - style ;) ) which defines the shared memory for the different clients
	Slots clients;
	//Now we should set up the server (C-style)
	
	//declaring some vars
	int sockfd, newsockfd;
    int portno = PORT;
    //a struct predefined in netinet/in.h
    struct sockaddr_in serv_addr, cli_addr; 
	
    //socklen_t is a kind of integer witch includes the lenght of the socketaddress
    socklen_t clilen; 
    
    //creating the socket. sockfd is an int. fd = filedescriptor
    //check http://www.linuxhowtos.org/C_C++/socket.htm 
    //socket() opens a new socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    //error handling
    if (sockfd < 0) 
       error("ERROR opening socket");

    //bzero sets all char to 0 of serv_addr
    bzero((char *) &serv_addr, sizeof(serv_addr));

    //setting the vars in the struct
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    //trying to bind
    //bind binds a socket to an address and dergelijke meer
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
             error("ERROR on binding");

    //listen:
    /*The listen system call allows the process to listen on the socket for connections. The first argument is the socket file descriptor, and the second is the size of the backlog queue, i.e., the number of connections that can be waiting while the process is handling a particular connection. This should be set to 5, the maximum size permitted by most systems. If the first argument is a valid socket, this call cannot fail, and so the code doesn't check for errors.*/
    listen(sockfd,5);

	//client address length
    clilen = sizeof(cli_addr);
    
    //pid: process identification: needed to fork
    int pid;
    
    //let the serveradmin know we're entering the while and the server till this point has been set up
    cout << "Done ..." << endl;
    cout << "Ready to accept connections (MAX 5)" << endl;
    
    //eternal while: as long as there are free slots, let people connect
    while (true) {
    	/***conditions for a new connection to enter***/
    	if(clients.numberof() < MAX_CLIENTS){
			//wait for a connection
        	newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        	//if accepting of the connection fails, report error
        	if (newsockfd < 0)
           		error("ERROR on accept");
        	//creating a new process
        	cout << "BEFORE FORK: "<<clients.numberof() << endl;
        	pid = fork();
        	//bij error
        	if (pid < 0)
            	error("ERROR on fork");
        	if (pid == 0){
    	   		//forked process
    	   		//close the OLD socket, so the new remains open
            	close(sockfd);
            	//using a new slot for a new client
        		clients.new_client();
            	//mainproces: just report to the log that a new client has connected
            	cout << "CHILD: "<<clients.numberof() << endl;
        		cout << "New client connected: ";
        		cout << " Total clients attached to server is now: " <<  clients.numberof() << "."<< endl;
            	//I made a new function for a forked process, because else the code gets too messy
            	forkedprocess(newsockfd, clients);
            	//exit this while, will never happen due an eternal while in the forkedprocess thing.
            	exit(0);
        	}
        	else{
        		cout << "MAIN: " << clients.numberof() << endl;
        		//close the NEW socket, the OLD one remains open
        		close(newsockfd);
        	}
        }
    } /* end of while */
	return 0; // will never happen
}
